package com.lambkit.core.http;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import com.lambkit.core.exception.LambkitException;
import com.lambkit.util.Printer;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Date;
import java.util.List;

/**
 * @author yangyong(孤竹行)
 */
public class ParamsBuilder {
    /***
     * 验证业务参数，和构建业务参数对象
     * @return
     */
    public Object[] buildParams(IHttpContext context, HttpAction action) throws LambkitException {
        Method method = action.getMethod();
        Printer.print(this, "web", method.getName());
        // javassist
        List<String> paramNames = getNames(method);
        // 反射获取api方法中参数类型
        Class<?>[] paramTypes = method.getParameterTypes(); // 反射

        Object[] args = new Object[paramTypes.length];
        if(paramTypes.length < 1) {
            return args;
        }
        // 校验api方法中是否存在对应的参数
//        for(String name : paramNames) {
//            if(context.get(name) == null) {
//                throw new LambkitException("调用失败：接口不存在‘" + name + "’参数");
//            }
//        }

        for (int i = 0; i < paramTypes.length; i++) {
            if (paramTypes[i].isAssignableFrom(IRequest.class)) {
                args[i] = context.getRequest();
            } else if (paramTypes[i].isAssignableFrom(IResponse.class)) {
                args[i] = context.getResponse();
            } else if (paramTypes[i].isAssignableFrom(IHttpContext.class)) {
                args[i] = context;
            } else if(BeanUtil.isBean(paramTypes[i]))  {
                args[i] = context.getBean(paramTypes[i], "");
            } else {
                args[i] = convert(context.get(paramNames.get(i)), paramTypes[i]);
            }
        }
        return args;
    }

    private List<String> getNames(Method method) {
        final int paraCount = method.getParameterCount();
        List<String> resultList = CollUtil.newArrayList();

        // 无参 action 共享同一个对象，该分支以外的所有 ParaProcessor 都是有参 action，不必进行 null 值判断
        if (paraCount == 0) {
            return resultList;
        }

        Parameter[] paras = method.getParameters();
        for (int i = 0; i < paraCount; i++) {
            Parameter p = paras[i];
            String parameterName = p.getName();
            //Printer.print(this, "web"("method param: " + parameterName);
            resultList.add(parameterName);
        }

        return resultList;
    }

    /**
     * 将MAP转换成具体的目标方方法参数对象
     */
    private <T> Object convert(String val, Class<T> targetClass) {
        Object result = null;
        if (val == null) {
            return null;
        } else if (Integer.class.equals(targetClass)) {
            result = Integer.parseInt(val.toString());
        } else if (Long.class.equals(targetClass)) {
            result = Long.parseLong(val.toString());
        } else if (Date.class.equals(targetClass)) {
            if (val.toString().matches("[0-9]+")) {
                result = new Date(Long.parseLong(val.toString()));
            } else {
                result = DateUtil.parse(val.toString());
            }
        } else if (String.class.equals(targetClass)) {
            result = val;
        } else {
            result = Convert.convert(targetClass, val);
        }
        return result;
    }
}
